package com.hzw.saas.web.admin.user.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hzw.saas.api.product.ILicenseProductService;
import com.hzw.saas.api.product.dto.LicenseProductExpireBO;
import com.hzw.saas.api.property.IPropertyService;
import com.hzw.saas.api.property.bo.PropertyBO;
import com.hzw.saas.api.property.enmus.SysDictKeyEnum;
import com.hzw.saas.api.property.enmus.SysDictModuleEnum;
import com.hzw.saas.api.user.*;
import com.hzw.saas.api.user.bo.*;
import com.hzw.saas.api.user.query.*;
import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.security.utils.SecurityUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.enums.AssertEnum;
import com.hzw.saas.web.admin.user.dto.AttributeDto;
import com.hzw.saas.web.admin.user.dto.ChannelDto;
import com.hzw.saas.web.admin.user.dto.LevelDtos;
import com.hzw.saas.web.admin.user.dto.RelationDto;
import com.hzw.saas.web.admin.user.param.*;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author zzl
 * @since 04/03/2021
 */
@Controller
@RequiredArgsConstructor
@Slf4j
@Api(tags = "客户信息管理")
public class CustomerController {

    private final MapperFacade mapperFacade;
    private final ICustomerService customerService;
    private final ICustomerLevelService customerLevelService;
    private final IUserRightsService userRightsService;
    private final ILicenseProductService licenseProductService;
    private final IStaffService staffService;
    private final IEmailService emailService;

    @Resource(name = IPropertyService.SYS_DICT_BEAN)
    private final IPropertyService<SysDictKeyEnum> propertyService;

    @GetMapping("/customer/exists/customerNo/{customerNo}")
    @ApiOperation(value = "检查客户编号是否存在", notes = "检查客户编号是否存在，一般用于登记客户信息时")
    @ApiResponses({
        @ApiResponse(code = 200, message = "true-存在，false-不存在")
    })
    @ApiOperationSort(11)
    public ResponseEntity<Boolean> existCustomerNo(@PathVariable String customerNo) {
        boolean b = customerService.existCustomer(new CustomerGetQuery().setCustomerNo(customerNo), AssertEnum.IGNORE);
        return ResponseEntity.ok(b);
    }

    @GetMapping("/customer/exists/phoneNo/{phoneNo}")
    @ApiOperation(value = "检查客户手机号是否存在", notes = "检查客户手机号是否存在，一般用于登记客户信息和更新客户信息时")
    @ApiResponses({
        @ApiResponse(code = 200, message = "true-存在，false-不存在")
    })
    @ApiOperationSort(12)
    public ResponseEntity<Boolean> existPhoneNo(@PathVariable String phoneNo) {
        boolean b = customerService.existCustomer(new CustomerGetQuery().setPhoneNo(phoneNo), AssertEnum.IGNORE);
        return ResponseEntity.ok(b);
    }

    @GetMapping("/customer/exists/email/{email}")
    @ApiOperation(value = "检查客户邮箱是否存在", notes = "检查客户邮箱是否存在，一般用于登记客户信息和更新客户信息时")
    @ApiResponses({
        @ApiResponse(code = 200, message = "true-存在，false-不存在")
    })
    @ApiOperationSort(13)
    public ResponseEntity<Boolean> existEmail(@PathVariable String email) {
        boolean b = customerService.existCustomer(new CustomerGetQuery().setEmail(email), AssertEnum.IGNORE);
        return ResponseEntity.ok(b);
    }

    @GetMapping("/customer/levels")
    @SysLog
    @ApiOperation(value = "获取全部会员等级列表", notes = "获取所有会员等级列表，含详细的权益信息")
    @ApiOperationSort(14)
    public ResponseEntity<List<CustomerLevelExpireBO>> listCustomerLevels() {
        List<CustomerLevelExpireBO> resultList = customerLevelService.listLevelsWithExpireTime();
        return ResponseEntity.ok(resultList);
    }

    @GetMapping("/customer/{customerLevelId}/licenses/")
    @SysLog
    @ApiOperation(value = "获取某会员等级的软件license列表", notes = "获取某会员等级下软件license列表，含license信息和过期时间等")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "customerLevelId", value = "会员等级ID", dataType = "String", required = true)
    })
    @ApiOperationSort(15)
    public ResponseEntity<List<LicenseProductExpireBO>> listLicenseProduct(@PathVariable String customerLevelId) {
        List<LicenseProductExpireBO> licenseProductBOList = this.licenseProductService.listLicenseByLevelWithExpireDate(customerLevelId);
        return ResponseEntity.ok(licenseProductBOList);
    }

    @PreAuthorize("@pms.hasAny('customer:list:all')")
    @GetMapping("/customers")
    @SysLog
    @ApiOperation(value = "获取客户信息列表", notes = "分页获取客户信息列表，支持模糊检索")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "fuzzyString", value = "检索内容，为空则查询所有数据", dataType = "String"),
        @ApiImplicitParam(name = "levelIds", value = "等级ID，可以指定多个等级，为空则查询所有数据", allowMultiple = true),
        @ApiImplicitParam(name = "isOpen", value = "是否开通，不传查全部，true｜开通，false｜没开通"),
        @ApiImplicitParam(name = "channelTypes", value = "注册渠道，不传查全部，可指定多个渠道", allowMultiple = true)
    })
    @ApiOperationSort(16)
    public ResponseEntity<IPage<CustomerBO>> listCustomers(PageParam pageParam,
                                                           @RequestParam(required = false) String fuzzyString,
                                                           @RequestParam(required = false) List<String> levelIds,
                                                           @RequestParam(required = false) Boolean isOpen,
                                                           @RequestParam(required = false) List<String> channelTypes) {
        IPage<CustomerBO> customerBOIPage = customerService.pageCustomers(pageParam, fuzzyString, levelIds, isOpen, channelTypes, null,null);
        return ResponseEntity.ok(customerBOIPage);
    }

    @PreAuthorize("@pms.hasAny('customer:list:self')")
    @GetMapping("/customers/self")
    @SysLog
    @ApiOperation(value = "获取自己的客户信息列表", notes = "分页获取客户信息列表，支持模糊检索")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "fuzzyString", value = "检索内容，为空则查询所有数据", dataType = "String"),
        @ApiImplicitParam(name = "levelIds", value = "等级ID，可以指定多个等级，为空则查询所有数据", allowMultiple = true),
        @ApiImplicitParam(name = "isOpen", value = "是否开通，不传查全部，true｜开通，false｜没开通"),
        @ApiImplicitParam(name = "channelTypes", value = "注册渠道，不传查全部，可指定多个渠道", allowMultiple = true),
        @ApiImplicitParam(name = "channelDesc",value = "渠道描述")
    })
    @ApiOperationSort(16)
    public ResponseEntity<IPage<CustomerBO>> myselfListCustomers(PageParam pageParam,
                                                           @RequestParam(required = false) String fuzzyString,
                                                           @RequestParam(required = false) List<String> levelIds,
                                                           @RequestParam(required = false) Boolean isOpen,
                                                           @RequestParam(required = false) List<String> channelTypes) {

        String userId = SecurityUtils.getUserId();
        StaffBO byId = staffService.getById(userId);
        ArrayList<String> stringArrayList = new ArrayList<>();
        stringArrayList.add(userId);
        if (StrUtil.isNotBlank(byId.getStaffPhoneNo())){
            stringArrayList.add(byId.getStaffPhoneNo());
        }
        if (CollectionUtil.isNotEmpty(byId.getStaffPhoneNoList())){
            stringArrayList.addAll(byId.getStaffPhoneNoList());
        }
        IPage<CustomerBO> customerBOIPage = customerService.pageCustomers(pageParam, fuzzyString, levelIds, isOpen, channelTypes, null,stringArrayList);
        return ResponseEntity.ok(customerBOIPage);
    }

    @SysLog(operation = "搜索客户邮箱列表")
    @ApiOperationSort(16)
    @GetMapping("/customer/emails")
    @ApiOperation(value = "搜索客户邮箱列表", notes = "搜索客户邮箱列表")
    public ResponseEntity<IPage<EmailBO>> listCustomerEmails(PageParam pageParam,
                                                              @RequestParam String keyword,
                                                              @RequestParam(required = false) @ApiParam(value = "1-客户，2-销售，不传-全部") Integer type) {
        return ResponseEntity.ok(emailService.listEmails(pageParam, keyword, type));
    }

    @GetMapping("/customer/{pid}")
    @SysLog
    @ApiOperation(value = "获取客户信息详情", notes = "根据客户PID获取客户信息详情")
    @ApiOperationSort(16)
    public ResponseEntity<CustomerBO> getCustomer(@PathVariable String pid) {
        CustomerBO customer = customerService.getCustomerDetailById(pid);
        AssertUtil.assertThrow("客户信息未找到!", Objects.isNull(customer));
        return ResponseEntity.ok(customer);
    }

    @PostMapping("/customer")
    @SysLog(operation = "登记客户信息", mode = 3)
    @ApiOperation(value = "登记客户信息", notes = "登记客户信息，客户服务登记线下客户信息。用户权益字段若无需自定义，请不要传递相关属性")
    @ApiOperationSort(17)
    public ResponseEntity<Void> addCustomer(@Validated @RequestBody CustomerAddParam param) {
        AssertUtil.assertThrow("手机和邮箱不可同时为空", StrUtil.isAllBlank(param.getPhoneNo(), param.getEmail()));
        // 后台注册，默认渠道B，渠道ID为staffId（工作人员ID）
        if (StrUtil.isBlank(param.getChannelType())) {
            param.setChannelType(SysDictKeyEnum.CHANNEL_B.getKey());
        }
        CustomerAddQuery customerAddQuery = mapperFacade.map(param, CustomerAddQuery.class);
        UserRightsProp userRightsProp = MapperUtil.nf().map(param, UserRightsProp.class);
        List<StaffCustomerRefParam> customerRefParams = param.getCustomerRefParams();
        if (CollectionUtil.isNotEmpty(customerRefParams)) {
            customerAddQuery.setCustomerRefQueries(mapperFacade.mapAsList(customerRefParams, StaffCustomerRefQuery.class));
        }
        customerService.registerCustomer(customerAddQuery, userRightsProp);

        return ResponseEntity.ok().build();
    }

    @PostMapping("/customer/account")
    @SysLog(operation = "创建客户云平台帐号", mode = 3)
    @ApiOperation(value = "创建客户云平台帐号", notes = "创建云平台帐号，一般为登记客户信息后调用")
    @ApiOperationSort(18)
    public ResponseEntity<Void> addUserAccount(@Validated @RequestBody CustomerAccountAddParam param) {
        UserAccountAddQuery userAccountAddQuery = mapperFacade.map(param, UserAccountAddQuery.class);
        customerService.createSaasUser(param.getCustomerNo(), userAccountAddQuery);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/customer/{customerNo}/rights")
    @SysLog
    @ApiOperation(value = "获取客户权益信息", notes = "获取客户权益信息")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "customerNo", value = "客户编号", dataType = "String", required = true)
    })
    @ApiOperationSort(19)
    public ResponseEntity<UserRightsBO> getUserRights(@PathVariable String customerNo) {
        CustomerBO customer = customerService.getCustomerByNo(customerNo);
        AssertUtil.assertThrow("客户不存在", Objects.isNull(customer));
        UserRightsBO userRights = userRightsService.getUserRightsByUser(customer.getUserId());
        return ResponseEntity.ok(userRights);
    }

    @GetMapping("/customer/{customerNo}/compare_level/{levelId}")
    @SysLog
    @ApiOperation(value = "客户等级调整权益对比", notes = "客户等级调整权益对比")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "customerNo", value = "客户编号", dataType = "String", required = true),
        @ApiImplicitParam(name = "levelId", value = "待比较的会员级别ID", dataType = "String", required = true)
    })
    @ApiOperationSort(20)
    public ResponseEntity<List<ValueCompareBO<?>>> compareUserWithNewLevel(@PathVariable String customerNo, @PathVariable String levelId) {
        CustomerBO customer = customerService.getCustomerByNo(customerNo);
        AssertUtil.assertThrow("客户不存在", Objects.isNull(customer));
        List<ValueCompareBO<?>> valueCompareBOS = userRightsService.compareUserRights(customer.getUserId(), levelId);
        return ResponseEntity.ok(valueCompareBOS);
    }

    @PutMapping("/customer")
    @PreAuthorize("@pms.hasAny('customer:update')")
    @SysLog(operation = "更新客户信息", mode = 3)
    @ApiOperation(value = "更新客户信息", notes = "更新客户信息，客户基本信息变动时进行更新。用户权益字段若无需自定义，请不要传递相关属性，若传递，则不会根据levelId调整相关权益")
    @ApiOperationSort(21)
    public ResponseEntity<Void> updateCustomer(@Validated @RequestBody CustomerUpdateParam param) {
        CustomerUpdateQuery customerUpdateQuery = mapperFacade.map(param, CustomerUpdateQuery.class);
        List<StaffCustomerRefParam> customerRefParams = param.getCustomerRefParams();
        if (CollectionUtil.isNotEmpty(customerRefParams)) {
            customerUpdateQuery.setCustomerRefQueries(mapperFacade.mapAsList(customerRefParams, StaffCustomerRefQuery.class));
        }
        UserRightsProp userRightsProp = MapperUtil.nf().map(param, UserRightsProp.class);
        customerService.updateCustomer(customerUpdateQuery, userRightsProp);
        return ResponseEntity.ok().build();
    }

    @PutMapping("/customer/level")
    @PreAuthorize("@pms.hasAny('customer:update')")
    @SysLog(operation = "更新客户会员级别", mode = 3)
    @ApiOperation(value = "更新客户会员级别", notes = "设置/更新会员级别/权益。用户权益字段若无需自定义，请不要传递相关属性，若传递，则不会根据levelId调整相关权益")
    @ApiOperationSort(22)
    public ResponseEntity<Void> updateCustomerLevel(@Validated @RequestBody CustomerLevelUpdateParam param) {
        CustomerUpdateQuery query = new CustomerUpdateQuery()
            .setCustomerNo(param.getCustomerNo())
            .setCustomerLevel(param.getCustomerLevel());
        UserRightsProp userRightsProp = MapperUtil.nf().map(param, UserRightsProp.class);
        customerService.updateCustomer(query, userRightsProp);
        return ResponseEntity.ok().build();
    }

    @DeleteMapping("/customer/{customerNo}")
    @SysLog(operation = "删除客户信息", mode = 3)
    @ApiOperation(value = "删除客户信息", notes = "删除客户信息，不再提供算力服务")
    @ApiOperationSort(23)
    @PreAuthorize("@pms.hasAny('customer:list:delete')")
    public ResponseEntity<Void> deleteCustomer(@PathVariable String customerNo) {
        customerService.deleteCustomerByNo(customerNo);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/customer/relation")
    @ApiOperationSort(24)
    @ApiOperation(value = "获取客户关系列表")
    public ResponseEntity<List<RelationDto>> getCustomerRelationList() {

        List<RelationDto> relationList = new ArrayList<>();

        List<PropertyBO> sysPropertyBOS = propertyService.listProperties(SysDictModuleEnum.RELATION.getModule());
        sysPropertyBOS.forEach(p -> {
            RelationDto relationDto = new RelationDto();
            relationDto.setRelationId(p.getKey());
            relationDto.setRelationName(p.getValue());
            relationList.add(relationDto);
        });

        return ResponseEntity.ok(relationList);
    }

    @GetMapping("/customer/channel")
    @ApiOperationSort(25)
    @ApiOperation(value = "获取渠道列表")
    public ResponseEntity<List<ChannelDto>> getChannelList() {

        List<ChannelDto> channels = new ArrayList<>();

        List<PropertyBO> sysPropertyBOS = propertyService.listProperties(SysDictModuleEnum.CHANNEL.getModule());
        sysPropertyBOS.forEach(p -> {
            ChannelDto channel = new ChannelDto();
            channel.setChannelId(p.getKey());
            channel.setChannelName(p.getValue());
            channels.add(channel);
        });

        return ResponseEntity.ok(channels);
    }

    @GetMapping("/customer/attribute")
    @ApiOperationSort(26)
    @ApiOperation(value = "查询条件的属性列表查询")
    public ResponseEntity<AttributeDto> findSearchList() {
        AttributeDto attributeDto = new AttributeDto();
        List<CustomerLevelBO> customerLevelBOS = customerLevelService.listLevels();
        List<LevelDtos> levelDtos = MapperUtil.nf().mapAsList(customerLevelBOS, LevelDtos.class);
        attributeDto.setLevelDtos(levelDtos);
        List<PropertyBO> channel = propertyService.listProperties(SysDictModuleEnum.CHANNEL.getModule());
        ArrayList<ChannelDto> channelDtos = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(channel)) {
            channel.forEach(p -> {
                ChannelDto channelDto = new ChannelDto();
                channelDto.setChannelId(p.getKey());
                channelDto.setChannelName(p.getValue());
                channelDtos.add(channelDto);
            });
        }
        attributeDto.setChannelDtos(channelDtos);
        return ResponseEntity.ok(attributeDto);
    }

}
